﻿module Time

open JulianDate

type Time = class
    val mutable private hour : int
    val mutable private minute : int
    val mutable private second : int

    member this.Hour
     with get() = this.hour
     and set((v:int)) = (this.hour <- v)

    member this.Minute
     with get() = this.minute
     and set((v:int)) = (this.minute <- v)

    member this.Second
     with get() = this.second
     and set((v:int)) = (this.second <- v)

    new() = { hour = 0; minute = 0; second = 0 }
    
end


let HoursMinutesSecondsToDecimalHours (hours:double, minute:double, second:double) =
    let decimalSeconds = System.Convert.ToDouble(second)/60.00
    let decimalMinutes = (decimalSeconds + System.Convert.ToDouble(minute))/60.00
    let decimalHours = System.Convert.ToDouble(hours) + decimalMinutes

    decimalHours

let DecimalHoursToHoursMinutesSeconds(input:double) =
    let mod1 = input%1.00
    let decMinutes = mod1 * 60.00
    let mod2 = decMinutes%1.00
    let decSeconds = mod2 * 60.00

    let year = System.Convert.ToInt32(System.DateTime.Now.Year)
    let month = System.Convert.ToInt32(System.DateTime.Now.Month)
    let day = System.Convert.ToInt32(System.DateTime.Now.Day)

    let GSTH = System.Convert.ToInt32(input - mod1)
    let GSTM = System.Convert.ToInt32(decMinutes)
    let GSTS = System.Convert.ToInt32(decSeconds)

    let time = new System.DateTime(year,month,day,GSTH,GSTM,GSTS)

    time


let DegreesMinutesSecondsToDecimalDegrees (degrees:double, minute:double, second:double) =
    let decimalSeconds = System.Convert.ToDouble(second)/60.00
    let decimalMinutes = (decimalSeconds + System.Convert.ToDouble(minute))/60.00
    let decimalHours = System.Convert.ToDouble(degrees) + decimalMinutes

    decimalHours

let HourAngleFromLocalSiderealTime (lsthours:double, lstminute:double, lstsecond:double, rahours:double, raminute:double, rasecond:double) =
    let LST = HoursMinutesSecondsToDecimalHours(lsthours, lstminute, lstsecond)
    let a = HoursMinutesSecondsToDecimalHours(rahours, raminute, rasecond)
    let hourAngle = LST - a

    hourAngle


let UniversalTimeToDecimalGreenwichSiderealTime (dt:System.DateTime) =
    let JD = JulianDate.CalculateJulianDate(dt)
    let S = JD - 2451545.0
    let T = S/36525.0
    let T0 = 6.697374558 + (2400.051336 * T) + (0.000025862 * T * T)

    let mutable n = T0
    while n <= 24.00 do
        n <- n + 24.00

    let T1 = n - 24.00

    let decimalSeconds = System.Convert.ToDouble(dt.Second)/60.00
    let decimalMinutes = (decimalSeconds + System.Convert.ToDouble(dt.Minute))/60.00
    let decimalHours = System.Convert.ToDouble(dt.Hour) + decimalMinutes

    let multUT = decimalHours * 1.002737909

    let mutable decimalGreenwichSiderealTime = multUT + T1

    let mutable GST =
//        if addToT1 > 24.00 then addToT1 - 24.00
//        else addToT1
          while decimalGreenwichSiderealTime >= 24.00 do
          decimalGreenwichSiderealTime <- decimalGreenwichSiderealTime - 24.00

    decimalGreenwichSiderealTime


let UniversalTimeToGreenwichSiderealTime (dt:System.DateTime) =
    let JD = JulianDate.CalculateJulianDate(dt)
    let S = JD - 2451545.0
    let T = S/36525.0
    let T0 = 6.697374558 + (2400.051336 * T) + (0.000025862 * T * T)

    let mutable n = T0
    while n <= 24.00 do
        n <- n + 24.00

    let T1 = n - 24.00

    let decimalSeconds = System.Convert.ToDouble(dt.Second)/60.00
    let decimalMinutes = (decimalSeconds + System.Convert.ToDouble(dt.Minute))/60.00
    let decimalHours = System.Convert.ToDouble(dt.Hour) + decimalMinutes

    let multUT = decimalHours * 1.002737909

    let mutable addToT1 = multUT + T1

    let mutable GST =
//        if addToT1 > 24.00 then addToT1 - 24.00
//        else addToT1
          while addToT1 >= 24.00 do
          addToT1 <- addToT1 - 24.00


    let time = DecimalHoursToHoursMinutesSeconds(addToT1)

    time

let GreenwichSiderealTimeToLocalSiderealTime (gst:double, longitude:double, cardinal:Coordinates.Cardinal) = 

    let decimalLong = longitude / 15.00
    let decimalLST = gst - decimalLong
    let localSiderealTime = DecimalHoursToHoursMinutesSeconds(decimalLST)

    localSiderealTime

let UniversalTimeToLocalSiderealTime (dt:System.DateTime, longitude:double, cardinal:Coordinates.Cardinal) = 

    let gst = UniversalTimeToGreenwichSiderealTime(dt)
    let decimalGst = HoursMinutesSecondsToDecimalHours(System.Convert.ToDouble(gst.Hour), System.Convert.ToDouble(gst.Minute), System.Convert.ToDouble(gst.Second))
    let localSiderealTime = GreenwichSiderealTimeToLocalSiderealTime(decimalGst, longitude, cardinal)

    localSiderealTime